package com.wang.jmonkey.ca.config;

import com.wang.jmonkey.ca.property.SecurityProperty;
import com.wang.jmonkey.common.constant.SecurityConstant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;

import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;

import java.util.Arrays;


/**
 * @Description 认证服务配置
 * @Author HeJiawang
 * @Date 2021/5/12 9:58
 */
@Configuration
@EnableAuthorizationServer
public class AuthenticationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private JwtAccessTokenConverter jwtAccessTokenConverter;

    @Autowired
    private TokenStore redisTokenStore;

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private SecurityProperty securityProperty;

    /**
     * 定义客户端详细信息服务
     * @param clients ClientDetailsServiceConfigurer
     * @throws Exception Exception
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient(SecurityConstant.clientsKey.Client_Id.getKey())
                .secret(passwordEncoder.encode(SecurityConstant.clientsKey.Client_Secret.getKey()))
                .authorizedGrantTypes(
                        SecurityConstant.clientsKey.Grant_Type_Refresh_Token.getKey(),
                        SecurityConstant.clientsKey.Grant_Type_Password.getKey()
                )
                .scopes(SecurityConstant.clientsKey.Scopes.getKey())
                .autoApprove(true);
    }

    /**
     * 定义令牌端点上的安全约束
     * @param security AuthorizationServerSecurityConfigurer
     * @throws Exception Exception
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.allowFormAuthenticationForClients();   // 启用客户端认证
    }

    /**
     * 定义授权和令牌端点以及令牌服务。
     * @param endpoints AuthorizationServerEndpointsConfigurer
     * @throws Exception Exception
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        // 增强token信息
        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        tokenEnhancerChain.setTokenEnhancers(
                Arrays.asList( jwtAccessTokenConverter )
        );

        endpoints.tokenEnhancer(tokenEnhancerChain)
                .tokenStore(redisTokenStore)
                .authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService);

        this.buildTokenServices(endpoints);
    }

    /**
     * 启用支持使用refresh token
     * @param endpoints endpoints
     */
    private void buildTokenServices(AuthorizationServerEndpointsConfigurer endpoints) {
        DefaultTokenServices tokenServices =
                (DefaultTokenServices) endpoints.getDefaultAuthorizationServerTokenServices();
        tokenServices.setTokenStore(endpoints.getTokenStore());
        tokenServices.setClientDetailsService(endpoints.getClientDetailsService());
        tokenServices.setTokenEnhancer(endpoints.getTokenEnhancer());
        // 支持使用refresh token刷新access token
        tokenServices.setSupportRefreshToken(true);
        // 允许重复使用refresh token
        tokenServices.setReuseRefreshToken(true);
        // access token有效期2个小时
        tokenServices.setAccessTokenValiditySeconds(securityProperty.getValiditySeconds().getAccessToken());
        // refresh token有效期30天
        tokenServices.setRefreshTokenValiditySeconds(securityProperty.getValiditySeconds().getRefreshToken());

        endpoints.tokenServices(tokenServices);
    }
}
